package phases

import (
	"fmt"
	"os/exec"
	"strconv"
	"strings"

	ckeapi "cke.io/ckectl/app/apis"
	"cke.io/ckectl/app/constants"
	"github.com/pkg/errors"
	kubeoptions "k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
	cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
)

var (
	watchPhaseExample = cmdutil.Examples(`
		# Writes a dynamic environment file with kubelet flags from a InitConfiguration file.
		kubeadm init phase kubelet-start --config config.yaml
		`)
)

type InstallInfo struct {
	Name       string
	Status     string
	Progress   string
	Message    string
}

// NewKubeletStartPhase creates a kubeadm workflow phase that start kubelet on a node.
func NewWatchPhase() workflow.Phase {
	return workflow.Phase{
		Name:    "watch",
		Short:   "Write kubelet settings and (re)start the kubelet",
		Long:    "Write a file with KubeletConfiguration and an environment file with node specific kubelet settings, and then (re)start kubelet.",
		Example: watchPhaseExample,
		Run:     runWatch,
		InheritFlags: []string{
			kubeoptions.CfgPath,
		},
	}
}

// runKubeletStart executes kubelet start logic.
func runWatch(c workflow.RunData) error {
	data, ok := c.(*ckeapi.WatchData)
	if !ok {
		return errors.New("error to load config from config path")
	}

	if len(data.Nodes) == 0 {
		fmt.Println("No resources found in this configration.")
		return nil
	}

	for _, node := range data.Nodes {
		fmt.Println( GetNodeInstallAllInfo(data.PhaseNum + 1, node))
	}

	return nil
}

func GetNodeInstallAllInfo(num int, node ckeapi.K8sNode) InstallInfo {
	msg := GetNodeInstallMsgs(node.Ip)

	if len(msg) != 0 && msg[len(msg)-1] == "Done" {
		return InstallInfo {
			Name:      node.Name,
			Status:    "OK",
			Progress:  "100%",
			Message:   "Done",
		}
	}

	var status, mss string
	if len(msg)!=0 && strings.Contains(msg[len(msg)-1], " Fail ") {
		status = "Failed"
	} else{
		status = "Installing"
	}

	// if mss is null, set it to start to install.
	if len(msg) == 0 {
		mss = "start to install node ..."
	}else {
		mss = msg[len(msg)-1]
	}

	return InstallInfo {
		Name:      node.Name,
		Status:    status,
		Progress:  strconv.Itoa(100*len(msg)/num) + "%",
		Message:   mss,
	}

}

func GetNodeInstallMsgs(ip string) []string {
	// #nosec
	out, err := exec.Command("ssh", ip, "-t", "cat " + constants.AnsibleUpDoneFile).CombinedOutput()
	if err != nil {
		return []string{}
	}

	return filterSpace(strings.Split(strings.ReplaceAll(string(out), "\r", ""), "\n"))
}

func filterSpace(oldSls []string) (newSls []string) {
	for _, word := range oldSls {
		if word != "" {
			newSls = append(newSls, word)
		}
	}
	return newSls
}